package com.school.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.school.dao.UserMapper;
import com.school.exception.ExcelDataException;
import com.school.exception.FileFormattingException;
import com.school.exception.UsernameAlreadyExistException;
import com.school.model.User;
import com.school.model.UserExample;
import com.school.utils.AssertUtil;
import com.school.utils.FileEnum;
import com.school.utils.RoleEnum;
import com.school.utils.Status;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Value("${file.path}")
    private String filePath;
    @Resource
    private UserMapper userMapper;
    @Autowired
    private UserRoleServiceImpl userRoleService;
    @Autowired
    private EmailServiceImpl emailService;

    @Value("${file.default.logo:logo.jpg}")
    private String defaultLogo;

    @Value("${file.default.logo:signature.jpg}")
    private String defaultSignature;
    @Autowired
    private PasswordEncoder passwordEncoder;

    public User queryByUsername(String username, User.Column... columns) {
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andUsernameEqualTo(username);
        criteria.andDeletedEqualTo((byte) 0);
        List<User> users = userMapper.selectByExampleSelective(userExample, columns);
        return users.size() == 0 ? null : users.get(0);

    }

    public User queryById(Integer id, User.Column... columns) {
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andIdEqualTo(id);
        criteria.andDeletedEqualTo((byte) 0);
        List<User> users = userMapper.selectByExampleSelective(userExample, columns);
        return users.size() == 0 ? null : users.get(0);
    }

    private void add(User user) {
        user.setAddTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        this.userMapper.insertSelective(user);
    }

    public PageInfo<User> querySelective(String schoolName,
                                         String contact,
                                         String address,
                                         String phone,
                                         String schoolCode,
                                         String location,
                                         String profession,
                                         String country,
                                         Integer addYear,
                                         Integer page,
                                         Integer pageSize,
                                         String sort,
                                         String order,
                                         User.Column... columns) {
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andDeletedEqualTo((byte) 0);
        if (StringUtils.hasText(sort) && StringUtils.hasText(order)) {
            userExample.setOrderByClause(sort + " " + order);
        }
        if (StringUtils.hasText(schoolName)) {
            criteria.andSchoolNameLike("%" + schoolName + "%");
        }

        if (StringUtils.hasText(contact)) {
            criteria.andContactLike("%" + contact + "%");
        }

        if (StringUtils.hasText(address)) {
            criteria.andAddressLike("%" + address + "%");
        }

        if (StringUtils.hasText(phone)) {
            criteria.andPhoneLike("%" + phone + "%");
        }
        if (!StringUtils.isEmpty(addYear)) {
            LocalDateTime end = LocalDateTime.of(addYear, 12, 31, 23, 59);
            LocalDateTime start = LocalDateTime.of(addYear, 1, 1, 0, 0);
            criteria.andAddTimeBetween(start, end);
        }

        if (StringUtils.hasText(schoolCode)) {
            criteria.andSchoolCodeLike("%" + schoolCode + "%");
        }

        if (StringUtils.hasText(location)) {
            criteria.andLocationLike("%" + location + "%");
        }
        if (StringUtils.hasText(profession)) {
            criteria.andProfessionLike("%" + profession + "%");
        }
        if (StringUtils.hasText(country)) {
            criteria.andCountryLike("%" + profession + "%");
        }
        if (page != null && pageSize != null) {
            //此时就已经拦截了sql语句执行完毕了；
            Page<User> users = PageHelper.startPage(page, pageSize);
            System.out.println(users);
        }
        List<User> users = null;
        if (columns.length != 0) {
            users = this.userMapper.selectByExampleSelective(userExample, columns);
        } else {
            users = this.userMapper.selectByExampleSelective(userExample);
        }
        return (PageInfo<User>) new PageInfo(users);
    }

    public int deleteById(Integer id) {
        return userMapper.deleteByPrimaryKey(id);
    }

    public int updateByIdSelective(User user) {
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andIdEqualTo(user.getId());
        user.setUpdateTime(LocalDateTime.now());
        return this.userMapper.updateByExampleSelective(user, userExample);
    }

    public int updateByUsernameSelective(User user) {
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andUsernameEqualTo(user.getUsername());
        user.setUpdateTime(LocalDateTime.now());
        return this.userMapper.updateByExampleSelective(user, userExample);
    }

    public User retrieveUserByToken() throws UsernameNotFoundException {
        UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return this.queryByUsername(principal.getUsername());
    }

    public void openLogin() {
        List<User> users = this.querySelective(User.Column.id).getList();
        Iterator var2 = users.iterator();
        while (var2.hasNext()) {
            User user = (User) var2.next();
            user.setAccountStatus((byte) 1);
            this.updateByIdSelective(user);
        }
    }

    public PageInfo<User> querySelective(Integer page, Integer pageSize, String sort, String order, User.Column... columns) {
        return querySelective(null, page, pageSize, sort, order, columns);
    }

    public PageInfo<User> querySelective(User.Column... columns) {
        return querySelective(null, null, null, null, columns);
    }

    public PageInfo<User> querySelective(String schoolName, Integer page, Integer pageSize, String sort, String order, User.Column... columns) {
        return querySelective(schoolName, null, null, null, null, null, null, null, null, page, pageSize, sort, order, columns);
    }

    public void importRegistrationForm(MultipartFile file) throws FileFormattingException, IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ExcelDataException, UsernameAlreadyExistException {
        String originalFilename = file.getOriginalFilename();
        String format = originalFilename.substring(originalFilename.lastIndexOf("."));
        AssertUtil.isExcel(format);
        Workbook workbook = null;
        if (format.equals(".xlsx")) {
            workbook = new XSSFWorkbook(file.getInputStream());
        } else {
            if (!format.equals(".xls")) {
                throw new FileFormattingException("文件格式不支持，仅支持.xls以及.xlsx");
            }
            workbook = new HSSFWorkbook(file.getInputStream());
        }
        int numberOfSheets = ((Workbook) workbook).getNumberOfSheets();
        label82:
        for (int i = 0; i < numberOfSheets; ++i) {
            Sheet sheetAt = ((Workbook) workbook).getSheetAt(i);
            Iterator<Row> rowIterator = sheetAt.iterator();
            Map info = null;
            if (rowIterator.hasNext()) {
                Row preRow = (Row) rowIterator.next();//第0行用于解析字段名
                info = this.preConstruct(preRow);
            }
            User user = null;
            while (rowIterator.hasNext()) {
                //现在开始每一行代表一个用户
                Row aRow = (Row) rowIterator.next();
                Constructor<User> constructor = User.class.getConstructor();
                user = (User) constructor.newInstance();
                Iterator cellIterator = aRow.iterator();
                //遍历该行的每一个元素
                while (cellIterator.hasNext()) {
                    Cell cell = (Cell) cellIterator.next();
                    CellType cellType = cell.getCellType();
                    cell.setCellType(CellType.STRING);
//                    System.out.println(cell.getRichStringCellValue());
                    RichTextString fieldValue = cell.getRichStringCellValue();
//                    if (cellType == CellType.NUMERIC) {
//                        fieldValue = String.valueOf(cell.getNumericCellValue()).trim();
//                    } else if (cellType == CellType.STRING) {
//                        fieldValue = cell.getStringCellValue().trim();
//                    }
                    int columnIndex = cell.getColumnIndex();
                    String fieldName = (String) info.get(columnIndex);
                    try {
                        this.invokeValue(user, fieldName, fieldValue.getString());
                    } catch (NoSuchMethodException var21) {
                        throw new ExcelDataException("Excel表中第一行字段与数据中的字段不对应！->" + fieldName);
                    }
                }
                //此时拼接完一个用户
                if (StringUtils.isEmpty(user.getUsername())) {
                    logger.warn("导入用户数据时，发现有一行用户名为空！");
                    continue;
                }
                try {
                    String defaultPassword = this.generateDefaultPassword();
//                    user.setPassword(bCryptPasswordEncoder.encode(defaultPassword));
                    user.setLogo(defaultLogo);
                    user.setSignature(defaultSignature);
                    this.emailService.sendVerificationCode("签约系统临时授权码", "签约系统临时授权码(3天内有效，请尽快重设您的密码)", user.getUsername(), 3, TimeUnit.DAYS);
                    user.setAccountStatus(Status.LOGIN_NOT_ALLOWED);
                    add(user, RoleEnum.USER.value());
                } catch (Exception e) {
                    this.logger.warn(user.getUsername() + "->" + e.getMessage());
                }
            }
        }
    }

    private String generateDefaultPassword() {
        String s = String.valueOf(System.currentTimeMillis());
        return s.substring(s.length() - 6);
    }

    private void invokeValue(User user, String fieldName, String fieldValue) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        Method method = User.class.getMethod("set" + fieldName, String.class);
        method.invoke(user, fieldValue);
    }


    private Map<Integer, String> preConstruct(Row aRow) {
        Map<Integer, String> map = new HashMap();
        Iterator<Cell> cellIterator = aRow.iterator();
        int var4 = 0;
        while (cellIterator.hasNext()) {
            Cell cell = (Cell) cellIterator.next();
            if (StringUtils.hasText(cell.getStringCellValue())) {
                map.put(var4++, cell.getStringCellValue());
            }
        }
        return map;
    }

    public void add(User user, int roleId) {
        add(user);
        userRoleService.add(user.getId(), roleId);
    }

    public Workbook exportRegistrationForm(List<User> users, Set<String> skipFieldSet) {
        Workbook workbook = new HSSFWorkbook();
        Sheet sheet = workbook.createSheet();
        Row row = sheet.createRow(0);
        Map<String, Integer> map = new HashMap();
        Field[] declaredFields = User.class.getDeclaredFields();
        int index = 0;
        Field[] var8 = declaredFields;
        int var9 = declaredFields.length;

        for (int var10 = 0; var10 < var9; ++var10) {
            Field declaredField = var8[var10];
            String fieldName = declaredField.getName();
            if (skipFieldSet.contains(fieldName)) {
                continue;
            }
            if (!fieldName.startsWith("IS_") && !fieldName.startsWith("NOT_")) {
                map.put(fieldName, index);
                Cell cell = row.createCell(index);
                ++index;
                cell.setCellValue(fieldName);
            }
        }
        for (int i = 1; i <= users.size(); ++i) {
            Row eachUserRow = sheet.createRow(i);
            Iterator var17 = map.entrySet().iterator();
            while (var17.hasNext()) {
                Map.Entry<String, Integer> entry = (Map.Entry) var17.next();
                Cell cell = eachUserRow.createCell(entry.getValue());
                try {
                    Object value = this.valueInvoke(users.get(i - 1), (String) entry.getKey());
                    cell.setCellValue(String.valueOf(value));
                } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException var14) {
                    var14.printStackTrace();
                }
            }
        }

        return workbook;
    }

    private Object valueInvoke(User user, String fieldName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        Method method = User.class.getMethod("get" + fieldName);
        return method.invoke(user);
    }

    public User upload(Integer userId, int value, MultipartFile file) throws IOException {
        User user = queryById(userId);
        Assert.notNull(user, "用户id不存在！");
        String location = this.retrieveRandomFileName((String) Objects.requireNonNull(file.getOriginalFilename()));
        File dist = new File(this.filePath + location);
        file.transferTo(dist);
        if (value == FileEnum.LOGO.value()) {
            user.setLogo(location);
        } else if (value == FileEnum.SIGNATURE.value()) {
            user.setSignature(location);
        }
        updateByIdSelective(user);
        return user;
    }

    private String retrieveRandomFileName(String fileName) {
        String format = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        UUID uuid = UUID.randomUUID();
        return uuid + "." + format;
    }

}
